package com.openbrew.openbrewpos;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import Models.POSGlassWare;
import Models.POSProductServingType;
import Models.POSProducts;
import Presenter.POSGlassWarePresenter;
import Presenter.POSProductServingTypePresenter;
import Presenter.POSProductsPresenter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.text.InputType;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;

public class ProductSetupView extends Activity {
	//Define class variables
	public ProgressDialog modalDialog = null;
	public ArrayList<POSProducts> products = null;
	public ArrayList<POSProductServingType> psts = null;
	public ArrayList<POSGlassWare> glasswares = null;
	public ArrayList<POSGlassWare>	remainingGlassware = null;
	
	//Indexes for class arrays.
	public int currentProductIdx = 0;
	public int selectedServingIdx = 0;
	
	//Place holders for views and components
	private ListView productListView;
	private ListView pstListView;
	private EditText descriptionText;
	private CheckBox onTapCheckbox;
	private CheckBox showUnTappedCheckbox;
	
	//Needed for popupMenu
	private PopupMenu popupMenu;
	private final static int ONE = 1;
	private final static int TWO = 2;
	
	//Variable for passing information to and from dialog.
	private String cost_text = "";

	//Create frame
	@SuppressLint("NewApi")
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_product_setup_view);
		//Initializations
		initializeComponents();
		initializePopupMenu();
		//Load listeners
		setCheckBoxListener();
		setPopupMenuListner();
		addListenerOnProductsList();
		setPSTListListener();
		//Load class arrays
		loadLists();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.product_setup_view, menu);
		return true;
	}
	
	/**********************************************************************************************
	 * Setup code.
	 **********************************************************************************************/
	private void initializeComponents(){
		showUnTappedCheckbox = (CheckBox) findViewById(R.id.product_settings_untapped);
		showUnTappedCheckbox.setChecked(false);
		onTapCheckbox = (CheckBox) findViewById(R.id.settings_productSetup_onTapCheckBox);
		productListView = (ListView) findViewById(R.id.product_setup_productList);
		pstListView = (ListView) findViewById(R.id.product_setup_list_servingTypes);
		descriptionText = (EditText) findViewById(R.id.text_settings_products_description);
		
		productListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
		productListView.setSelector(android.R.color.darker_gray);
	}
	
	private void initializePopupMenu(){
		popupMenu = new PopupMenu(this, findViewById(R.id.product_setup_list_servingTypes));
        popupMenu.getMenu().add(Menu.NONE, ONE, Menu.NONE, "Change Price");
        popupMenu.getMenu().add(Menu.NONE, TWO, Menu.NONE, "Remove Serving Type");
	}
	
	private void setCheckBoxListener(){
		showUnTappedCheckbox.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View arg0){
				displayProductsToList();
				displayFirstItemOnProductList();
			}
		});
	}
	
	private void setPopupMenuListner(){
		popupMenu.setOnMenuItemClickListener(new OnMenuItemClickListener(){
			@Override
			public boolean onMenuItemClick(MenuItem item){
				switch(item.getItemId()){
				case ONE:
					getAndUpdateCost();
					break;
				case TWO:
					removePSTFromProduct();
					break;
				}
				return false;
			}
		});
	}
	
	private void addListenerOnProductsList(){
		productListView.setOnItemClickListener(new OnItemClickListener(){
			@Override
		    public void onItemClick(AdapterView<?> parentView, View selectedItemView, int position, long id) {
				final String selection = (String) parentView.getItemAtPosition(position);
				POSProducts product = getProductFromCache(selection);
		        if(product != null){
					setProductDisplayData(product);
		        }
		    }
		});
	}
	
	private void setPSTListListener(){
		pstListView.setOnItemLongClickListener(new OnItemLongClickListener(){
			public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int pos, long id) {
				selectedServingIdx = pos;
                popupMenu.show();
                return true;
            }
		});
	}
	
	/**********************************************************************************************
	 * Code to load class arrays
	 **********************************************************************************************/
	private void loadLists(){
		//Load all glassware
		getAllGlasswares();
		//getAllProducts (Called from glassware Async task).
	}
	
	private void getAllGlasswares(){
		modalDialog = ProgressDialog.show(this, null, "Loading Glassware...");
		final String strStart = getURLString();
		final String str = "posglassware";
		new DownloadAllPOSGlasswareTask().execute(strStart+str, getUSERString(), getPASSString());
	}
	
	private void getAllProducts(){
		modalDialog = ProgressDialog.show(this, null, "Loading Products...");
		final String strStart = getURLString();
		final String str = "posproducts";
		new DownloadPOSProductsTask().execute(strStart+str, getUSERString(), getPASSString());
	}
	
	private void doProductUpdate(final POSProducts product){
		modalDialog = ProgressDialog.show(this, null, "Updating Product...");
		final String strStart = getURLString();
		final String str = "posproducts";
		POSProductsPresenter presenter = new POSProductsPresenter();
		new UpdatePOSProductsTask().execute(strStart+str, getUSERString(), getPASSString(), presenter.createJSON(product).toString());
	}
	
	private void doRemovePSTFromProduct(final POSProductServingType pst){
		modalDialog = ProgressDialog.show(this, null, "Deleting Serving Type...");
		final String strStart = getURLString();
		final String str = "posproductservingtype";
		new DeletePSTTask().execute(strStart+str, getUSERString(), getPASSString(), Integer.toString(pst.getId()));
	}
	
	public void doUpdateServingType(final POSProductServingType pst){
		modalDialog = ProgressDialog.show(this, null, "Updating Serving Type...");
		final String strStart = getURLString();
		final String str = "posproductservingtype";
		POSProductServingTypePresenter presenter = new POSProductServingTypePresenter();
		new UpdatePOSProductServingTypeTask().execute(strStart+str, getUSERString(), getPASSString(), presenter.createJSON(pst).toString());
	}
	
	public void doInsertServingType(final POSProductServingType pst){
		modalDialog = ProgressDialog.show(this, null, "Inserting Serving Type...");
		final String strStart = getURLString();
		final String str = "posproductservingtype";
		POSProductServingTypePresenter presenter = new POSProductServingTypePresenter();
		new InsertPOSProductServingTypeTask().execute(strStart+str, getUSERString(), getPASSString(), presenter.createJSON(pst).toString());
	}
	
	/**********************************************************************************************
	 * Functions to get URL String data
	 **********************************************************************************************/
	private String getURLString(){
		//create server address from preferences.
		/*SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
		String port = sharedPrefs.getString("prefConnPortKey", "");
		String server = sharedPrefs.getString("prefServerKey", "");
		String path = sharedPrefs.getString("prefPathKey", "");
		String serverUser = sharedPrefs.getString("prefServerUser", "");
		String serverPass = sharedPrefs.getString("prefServerPass", "");
		final String strStart = server + ":" + port + path;
		final String str = "customergroup";*/
		String port = "8181";
		String server = "https://www.charteredtech.net";
		String path = "/openBrewRF-1.0/webresources/com.openbrew.openbrewrf.";
		final String strStart = server + ":" + port + path;
		return strStart;
	}
	
	private String getUSERString(){
		//SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
		//String serverUser = sharedPrefs.getString("prefServerUser", "");
		String serverUser = "openBrewClient";
		return serverUser;
	}
	
	private String getPASSString(){
		//SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
		//String serverPass = sharedPrefs.getString("prefServerPass", "");
		String serverPass = "0p3nBr3w.547";
		return serverPass;
	}
	
	/**********************************************************************************************
	 * Async Classes for RESTFul Connection
	 **********************************************************************************************/
	private class DownloadAllPOSGlasswareTask extends AsyncTask<String, Void, String> {
    	@Override
        protected String doInBackground(String... urls) {

            try {
                return RESTfulConnect.getResource(urls[0], urls[1], urls[2]);
            } catch (IOException e) {
            	e.printStackTrace();
            	return "Connection Error";
            }
        }
    	@Override
        protected void onPostExecute(String result) {
    		POSGlassWarePresenter glasswarePresenter = new POSGlassWarePresenter();
    		glasswares = glasswarePresenter.tryJSONParseArray(result);
    		modalDialog.dismiss();
    		//Now load all products
    		getAllProducts();
        }
    }
	
	private class DownloadPOSProductsTask extends AsyncTask<String, Void, String> {
    	@Override
        protected String doInBackground(String... urls) {

            try {
                return RESTfulConnect.getResource(urls[0], urls[1], urls[2]);
            } catch (IOException e) {
            	e.printStackTrace();
            	return "Connection Error";
            }
        }
    	@Override
        protected void onPostExecute(String result) {
    		POSProductsPresenter productPresenter = new POSProductsPresenter();
    		products = productPresenter.tryJSONParseArray(result);
    		modalDialog.dismiss();
    		loadInitialView();
        }
    }
	
	private class UpdatePOSProductsTask extends AsyncTask<String, Void, String> {
    	@Override
        protected String doInBackground(String... urls) {
            try {
                return RESTfulConnect.putResource(urls[0], urls[1], urls[2], urls[3]);
            } catch (IOException e) {
            	e.printStackTrace();
            	return "Connection Error";
            }
        }
    	@Override
        protected void onPostExecute(String result) {
    		modalDialog.dismiss();
    		displayProductsToList();
			displayFirstItemOnProductList();
        }
    }
	
	private class DeletePSTTask extends AsyncTask<String, Void, String> {
    	@Override
        protected String doInBackground(String... urls) {
            try {
                return RESTfulConnect.deleteResource(urls[0], urls[1], urls[2], urls[3]);
            } catch (IOException e) {
            	e.printStackTrace();
            	return "Connection Error";
            }
        }
    	@Override
        protected void onPostExecute(String result) {
    		modalDialog.dismiss();
    		psts.remove(selectedServingIdx);
    		POSProducts product = products.get(currentProductIdx);
    		product.setProductServingTypes(psts);
    		setProductDisplayData(product);
        }
    }
	
	private class UpdatePOSProductServingTypeTask extends AsyncTask<String, Void, String> {
    	@Override
        protected String doInBackground(String... urls) {
            try {
                return RESTfulConnect.putResource(urls[0], urls[1], urls[2], urls[3]);
            } catch (IOException e) {
            	e.printStackTrace();
            	return "Connection Error";
            }
        }
    	@Override
        protected void onPostExecute(String result) {
    		modalDialog.dismiss();
    		setProductDisplayData(products.get(currentProductIdx));
        }
    }
	
	private class InsertPOSProductServingTypeTask extends AsyncTask<String, Void, String> {
    	@Override
        protected String doInBackground(String... urls) {
            try {
                return RESTfulConnect.postResource(urls[0], urls[1], urls[2], urls[3]);
            } catch (IOException e) {
            	e.printStackTrace();
            	return "Connection Error";
            }
        }
    	@Override
        protected void onPostExecute(String result) {
    		//Log.d("This is the output", result);
    		POSProductServingTypePresenter pstPresenter = new POSProductServingTypePresenter();
    		try{
	    		modalDialog.dismiss();
	    		JSONObject json = new JSONObject(result);
	    		POSProductServingType p = pstPresenter.createPSTFromJSONObject(json);
	    		POSProducts product = products.get(currentProductIdx);
	    		List<POSProductServingType> types = new ArrayList<POSProductServingType>();
	    		if(product.getProductServingTypes()!=null){
	    			types = product.getProductServingTypes();
	    		}
				types.add(p);
				product.setProductServingTypes(types);
				doProductUpdate(product);
    		} catch(JSONException ex){
    			ex.printStackTrace();
    		} 
        }
    }
	
	/**********************************************************************************************
	 * Functions to display data on the screen.
	 **********************************************************************************************/
	private void loadInitialView(){
		displayProductsToList();
		displayFirstItemOnProductList();
	}
	
	private void displayProductsToList(){
		List<String> list = new ArrayList<String>();
		for(final POSProducts product : products){
			if(product.isOnTap() == !showUnTappedCheckbox.isChecked()){
				list.add(product.getDisplayString());
			}
		}
		ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
				android.R.layout.simple_list_item_1, list);
		productListView.setAdapter(dataAdapter);
	}
	
	private void displayFirstItemOnProductList(){
		if(productListView.getCount()!=0){
			final String selection = (String) productListView.getItemAtPosition(0);
			POSProducts product = getProductFromCache(selection);
			if(product != null){
				setProductDisplayData(product);
	        }
		}
	}
	
	private POSProducts getProductFromCache(final String s){
		if(s.isEmpty()){
			return null;
		}
		int idx = 0;
		for(final POSProducts product : products){
			if(product.getDisplayString().equals(s)){
				currentProductIdx = idx;
				return product;
			}
			idx++;
		}
		return null;
	}
	
	private void setProductDisplayData(final POSProducts product){
		descriptionText.setText(product.getDescription());
		onTapCheckbox.setChecked(product.isOnTap());
		if(product.getProductServingTypes() != null){
			psts = (ArrayList<POSProductServingType>) product.getProductServingTypes();
			pstListView = (ListView) findViewById(R.id.product_setup_list_servingTypes);
			List<String> list = new ArrayList<String>();
			for(final POSProductServingType pst : psts){
				list.add(pst.getPSTString());
			}
			ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
					android.R.layout.simple_list_item_1, list);
			pstListView.setAdapter(dataAdapter);
		} else {
			psts = new ArrayList<POSProductServingType>();
			List<String> list = new ArrayList<String>();
			ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
					android.R.layout.simple_list_item_1, list);
			pstListView.setAdapter(dataAdapter);
		}
	}
	
	/**********************************************************************************************
	 * Functions to Update Product
	 **********************************************************************************************/
	public void updateProduct(View view){
		POSProducts product = products.get(currentProductIdx);
		product.setDescription(descriptionText.getText().toString());
		product.setOnTap(onTapCheckbox.isChecked());
		doProductUpdate(product);
	}
	
	/**********************************************************************************************
	 * Functions to Maintain and Update Product PSTs
	 **********************************************************************************************/
	private void removePSTFromProduct(){
		POSProductServingType pst = psts.get(selectedServingIdx);
		doRemovePSTFromProduct(pst);
	}
	
	private void getAndUpdateCost(){
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("Enter New Price");
		final EditText input = new EditText(this);
		//input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
		input.setInputType(InputType.TYPE_CLASS_TEXT);
		builder.setView(input);
		builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				POSProductServingType pst = psts.get(selectedServingIdx);
				cost_text = input.getText().toString();
				final double cost = Double.parseDouble(cost_text.trim());
				pst.setCost(cost);
				doUpdateServingType(pst);
			}
		});
		builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.cancel();
			}
		});
		builder.show();
	}
	
	/**********************************************************************************************
	 * Functions to Insert a new PST
	 **********************************************************************************************/
	public boolean addServingType(View view){
		setRemainingGlassware();
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("Select Serving Type To Add:");
		List<String> list = new ArrayList<String>();
		for(final POSGlassWare glassware : remainingGlassware){
			list.add(glassware.getDisplayString());
		}
		final String[] items = list.toArray(new String[0]);
		builder.setItems(items, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				POSGlassWare glassware = getGlassWareFromCacheViaDesc(items[which]);
				POSProducts product = products.get(currentProductIdx);
				POSProductServingType pst = new POSProductServingType();
				pst.setBeer(product.getBeer());
				pst.setCost(0);
				pst.setGlassWare(glassware);
				pst.setId(0);
				getCostAndInsertPST(pst);
			}
		});
		builder.show();
		return true;
	}
	
	private void getCostAndInsertPST(final POSProductServingType pst){
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("Enter Price");
		final EditText input = new EditText(this);
		input.setInputType(InputType.TYPE_CLASS_TEXT);
		builder.setView(input);
		builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				cost_text = input.getText().toString();
				final double cost = Double.parseDouble(cost_text.trim());
				pst.setCost(cost);
				doInsertServingType(pst);
			}
		});
		builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.cancel();
			}
		});
		builder.show();
	}
	
	private void setRemainingGlassware(){
		remainingGlassware = new ArrayList<POSGlassWare>();
		for(final POSGlassWare glassware : glasswares){
			boolean add = true;
			if(psts != null){
				for(final POSProductServingType p : psts){
					if(glassware.getId() == p.getGlassWare().getId()){
						add = false;
					}
				}
			}
			if(add){
				remainingGlassware.add(glassware);
			}
		}
	}

	private POSGlassWare getGlassWareFromCacheViaDesc(final String str){
		for(final POSGlassWare glassware : glasswares){
			if(glassware.getDisplayString().equals(str)){
				return glassware;
			}
		}
		return null;
	}

}
